-- 查找函数的local变量
function get_local( func, name )
    local i=1
    local v_name, value
    while true do
        v_name, value = debug.getlocal(func,i)
        if not v_name or v_name == name then
            break
        end
        i = i+1
    end
    if v_name and v_name == name then
        return value
    end
    return nil
end

-- 修改函数的local变量
function set_local( func, name, value )
    local i=1
    local v_name
    while true do
        v_name, _ = debug.getlocal(func,i)
        if not v_name or v_name == name then
            break
        end
        i = i+1
    end
    if not v_name then
        return false
    end

    debug.setlocal(func,i,value)
    return true
end

-- 修改函数的upvalue
function get_upvalue( func, name )
    local i=1
    local v_name, value
    while true do
        v_name, value = debug.getupvalue(func,i)
        if not v_name or v_name == name then
            break
        end
        i = i+1
    end
    if v_name and v_name == name then
        return value
    end
    return nil
end

-- 修改函数的upvalue
function set_upvalue( func, name, value )
    local i=1
    local v_name
    while true do
        v_name, _ = debug.getupvalue(func,i)
        if not v_name or v_name == name then
            break
        end
        i = i+1
    end
    if not v_name then
        return false
    end

    debug.setupvalue(func,i,value)
    return true
end

function dump(obj)
    local getIndent, quoteStr, wrapKey, wrapVal, dumpObj
    getIndent = function(level)
        return string.rep("\t", level)
    end
    quoteStr = function(str)
        return '"' .. string.gsub(str, '"', '\\"') .. '"'
    end
    wrapKey = function(val)
        if type(val) == "number" then
            return "[" .. val .. "]"
        elseif type(val) == "string" then
            return "[" .. quoteStr(val) .. "]"
        else
            return "[" .. tostring(val) .. "]"
        end
    end
    wrapVal = function(val, level)
        if type(val) == "table" then
            return dumpObj(val, level)
        elseif type(val) == "number" then
            return val
        elseif type(val) == "string" then
            return quoteStr(val)
        else
            return tostring(val)
        end
    end
    dumpObj = function(obj, level)
        if type(obj) ~= "table" then
            return wrapVal(obj)
        end
        level = level + 1
        local tokens = {}
        tokens[#tokens + 1] = "{"
        for k, v in pairs(obj) do
            tokens[#tokens + 1] = getIndent(level) .. wrapKey(k) .. " = " .. wrapVal(v, level) .. ","
        end
        tokens[#tokens + 1] = getIndent(level - 1) .. "}"
        return table.concat(tokens, "\n")
    end
    return dumpObj(obj, 0)
end
